package com.hframe.filter;

import com.hframe.data.DSearchEngine;
import com.hframe.type.TArray;
import com.hframe.type.TString;
import org.apache.log4j.Logger;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;

/**
 * 访问统计
 * 初始化参数
 * Exclude 要排除的路径  如 /html/,/home/ 多个路径用‘，’号格
 * StatType 只统计的后缀名  如 .jps,.html 多个后缀用‘，’号格
 * <p>
 * <p>
 * Created by heqian on 17-11-6.
 */
public abstract class StatFilter implements Filter {
    private static Logger log = Logger.getLogger(StatFilter.class);
    private String exclude[] = {};
    private String[] type = {};

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        String temp = filterConfig.getInitParameter("StatType");
        if (null != temp) {
            type = temp.split(",");
        }

        temp = filterConfig.getInitParameter("Exclude");
        if (null != temp) {
            exclude = temp.split(",");
        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response = ((HttpServletResponse) servletResponse);
        filterChain.doFilter(servletRequest, servletResponse);

        if (200 == response.getStatus() && !isExpel((HttpServletRequest) servletRequest)) {
            if (!checkSpider((HttpServletRequest) servletRequest)) {
                response.setStatus(400);
                return;
            }
        }
    }

    private boolean isExpel(HttpServletRequest servletRequest) {
        String url = servletRequest.getRequestURI();
        for (String item : exclude) {
            if (0 == url.indexOf(item)) {
                return true;
            }
        }

        if (url.endsWith("/")) {
            return false;
        }

        for (String item : type) {
            if (url.endsWith(item)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 检查搜索引擎爬虫
     *
     * @param request
     * @return
     * @throws IOException
     */
    private boolean checkSpider(HttpServletRequest request) throws IOException {
        String ip = getIpAddress(request);
        String agent = request.getHeader("User-Agent");
        int port = request.getServerPort();
        String url = request.getScheme() + "//" + request.getServerName() + (80 == port ? "" : ":" + port) + request.getRequestURI();

        ArrayList<DSearchEngine> array = getSearchEngine();

        if (null != array) {
            for (DSearchEngine item : array) {
                if (0 < agent.indexOf(item.spider.get())) {
                    if (!checkIp(ip, item.ips)) {
                        return false;
                    }
                    onSearchEngine(request, url, item);
                    return true;
                }
            }
        }

        String referer = request.getHeader("Referer");
        String query = request.getQueryString();
        onRequest(request, url += null == query ? "" : "?" + query, (String) request.getSession().getAttribute("LastRequestURI"), referer, ip);
        request.getSession().setAttribute("LastRequestURI", url);
        return true;
    }

    protected abstract void onRequest(HttpServletRequest request, String url, String last, String referer, String ip);


    protected abstract void onSearchEngine(HttpServletRequest request, String url, DSearchEngine item);

    private boolean checkIp(String ip, TArray<TString> ips) {
        for (TString item : ips.get()) {
            if (item.equals(ip)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获得搜索引擎列表
     *
     * @return
     */
    protected ArrayList<DSearchEngine> getSearchEngine() {
        return null;
    }

    /**
     * 获得访问请求真实地址
     *
     * @param request
     * @return
     * @throws IOException
     */
    protected String getIpAddress(HttpServletRequest request) throws IOException {
        // 获取请求主机IP地址,如果通过代理进来，则透过防火墙获取真实IP地址

        String ip = request.getHeader("X-Forwarded-For");

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        } else if (ip.length() > 15) {
            String[] ips = ip.split(",");
            for (int index = 0; index < ips.length; index++) {
                String strIp = (String) ips[index];
                if (!("unknown".equalsIgnoreCase(strIp))) {
                    ip = strIp;
                    break;
                }
            }
        }
        return ip;
    }
}
